<?php

require_once FRAMEWORK_PATH . 'contentpage.php';

class Template extends ContentPage {
	private $_filename;
	private $_function;
	private $_lastModified = 0;
	private $_isCachable = false;

	public static function Fetch($filename) {
		$templateDir = INCLUDE_PATH . DIRECTORY_SEPARATOR . 'templates';
		$compiledDir = $templateDir . DIRECTORY_SEPARATOR . 'compiled';

		if (!file_exists($compiledDir)) {
			if (!@mkdir($compiledDir)) {
				throw new Exception('Failed to create compiled template directory.');
			}
		}

		if (substr($filename, -4) != '.det') {
			$filename = $templateDir . DIRECTORY_SEPARATOR . $filename . '.det';
		} else {
			$filename = realpath($filename);
		}

		if (!$filename || !file_exists($filename)) {
			throw new Exception('Template file ' . $filename . ' not found');
		}

		$md5 = md5($filename);
		$function = 'template_' . $md5;
		$compiled = $compiledDir . DIRECTORY_SEPARATOR . $md5 . '-' . filemtime($filename) . '.php';

		if (!file_exists($compiled)) {
			$file_data = "<?php\n\nfunction $function(\$o) {\nglobal \$config;\nextract(\$o, EXTR_SKIP);\n";
			$file_data .= self::Compile($filename);
			$file_data .= "\n}";

			if (!file_put_contents($compiled, $file_data)) {
				throw new Exception('Failed to write compiled template ' . $compiled);
			} else {
				//$syntaxResult = syntax_check($compiled);
				//if (substr_count($syntaxResult, 'No syntax errors') == 0) {
					//$file_data = $file_begin . "echo \"" . addcslashes($syntaxResult, "$\"\r\n\t\0") . "\";\n";
					//@file_put_contents($compiled, $file_data);
				//}
			}
		}

		return new self($compiled, $function);
	}

	public static function Compile($filename) {
		$file = @file_get_contents($filename, true); //FILE_USE_INCLUDE_PATH );

		$code = '';
		$lastpos = 0;
		$lines = explode("\n", $file);

		foreach ($lines as $line) {
			$t = trim($line);
			$l = strlen($t);
			if($l >= 4) {
				$v = $t[0].$t[1].$t[$l-2].$t[$l-1];
				if ('<##>' == $v && $t[2] != '=') {
					$file = str_replace($line . "\n", $t, $file);
				} else if ('<!!>' == $v) {
					$file = str_replace($line . "\n", '', $file);
				}
			}
		}

		while (($pos = strpos($file, '<#', $lastpos)) !== false) {
			$code .= self::EchoBetween($file, $pos, $lastpos);

			$lastpos = strpos($file, '#>', $pos) + 2;
			$txt = trim(substr($file, $pos + 2, $lastpos - $pos - 4));
			$endchr = $txt[strlen($txt) - 1];

			if (!($endchr == ';' || $endchr == ':')) {
				$txt .= ';';
			}

			if ($txt[0] == '=') {
				$txt = "echo " . substr($txt, 1, strlen($txt) - 1);
			}

			$code .= $txt . "\n";
		}

		$code .= self::EchoBetween($file, strlen($file), $lastpos);

		return $code;
	}

	private static function RegisterNamespace($namespace, $class) {
		//if (version_compare(phpversion(), '5.3.0', '>=')) {}

		if (is_object($class) && $class instanceof TemplateNamespace) {
			
		}
	}

	private static function EchoBetween($file, $pos, $lastpos) {
		if ($pos - $lastpos > 0) {
			$txt = substr($file, $lastpos, $pos - $lastpos);
			return "echo \"" . addcslashes($txt, "$\"\r\n\t\0") . "\";\n";
		} else {
			return "";
		}
	}


	private $_vars = array();

	private function __construct($filename, $function) {
		$this->_filename = $filename;
		$this->_function = $function;
	}

	/*
	 * Implementation of abstract function from parent
	 * Render()
	 */
	public function Render() {
		try {
			ob_start();
			$this->Run();
			return ob_get_clean();
		} catch (Exception $ex) {
			ob_end_clean();
			throw $ex;
		}
	}

	/*
	 * Stub implementation of abstract function from parent
	 * GetUUID()
	 */
	public function GetUUID() {
		return $this->_filename;
	}

	/*
	 * Stub implementation of abstract function from parent
	 * LastModified()
	 */
	public function LastModified() {
		//$mtime = @filemtime( $this->_filename );
		//return $mtime > $this->_lastModified ? $mtime : $this->_lastModified;
		return $this->_lastModified;
	}

	public function SetLastModified($value) {
		$this->_lastModified = $value;

/*		if (!is_array($value)) {
			$value = array($value);
		}
		$value[] = @filemtime($this->_filename);
		$this->_lastModified = $value; */
	}

	/*
	 * Stub implementation of abstract function from parent
	 * IsCachable()
	 */
	public function IsCachable() {
		return $this->_isCachable;
	}

	public function AllowCaching($value) {
		$this->_isCachable = $value;
	}

	public function Run() {
		//extract($this->_vars);
		include_once $this->_filename;
		call_user_func($this->_function, $this->_vars);
	}

	public function __set($name, $value) {
		$this->_vars[$name] = $value;
	}

	public function __get($name) {
		return $this->_vars[$name];
	}

	public function setVar($name, $value) {
		$this->_vars[$name] = $value;
	}

	public function getVar($name) {
		return $this->_vars[$name];
	}

	public function getVars() {
		return clone $this->_vars;
	}

	public function setVars(array $values) {
		foreach ($values as $key => $val) {
			$this->_vars[$key] = $val;
		}
	}

	public function resetVars() {
		$this->_vars = array();
	}
}

interface TemplateNamespace {
	//public function 
}
